#include "IncidenceGraph.h"


const Edge Edge::Null = Edge(-1, -1, 0);


IncidenceGraph::IncidenceGraph()
{
}


IncidenceGraph::~IncidenceGraph()
{
}


void IncidenceGraph::AddVertex(int i)	
{
	if (ContainsVertex(i))
		return;

	if (i < 1)
		return;

	incidences.insert(pair<int, Edge>(i, Edge::Null));
}


void IncidenceGraph::RemoveVertex(int i)
{
	incidences.erase(i);
}


bool IncidenceGraph::ContainsVertex(int i) const
{
	return incidences.find(i) != incidences.end();
}


list<int> IncidenceGraph::GetVertices() const
{
	auto l = list<int>();
	for (auto it = incidences.begin(); it != incidences.end(); it = incidences.upper_bound(it->first)) {
		l.push_back(it->first);
	}
	return l;
}


int IncidenceGraph::EdgeCount(int i) const
{
	auto n = 0;
	auto i_range = incidences.equal_range(i);
	for (auto it = i_range.first; it != i_range.second; it++) {
		if (it->second.i == i) n++;
	}
	return n;
}


int IncidenceGraph::VertexCount() const
{
	auto n = 0;
	for (auto it = incidences.begin(); it != incidences.end(); it = incidences.upper_bound(it->first)) {
		n++;
	}
	return n;
}


void IncidenceGraph::AddDirectedEdge(int i, int j, double weight, bool addVertices)
{
	if (weight <= 0)
		return;

	if (addVertices) {
		AddVertex(i);
		AddVertex(j);
	}
	
	auto i_range = incidences.equal_range(i);
	for (auto it = i_range.first; it != i_range.second; it++) {
		if (it->second.i == i && it->second.j == j)
			return;
	}

	incidences.insert(pair<int, Edge>(i, Edge(i, j, weight)));
}


void IncidenceGraph::AddUndirectedEdge(int i, int j, double weight, bool addVertices)
{
	if (weight <= 0)
		return;

	if (addVertices) {
		AddVertex(i);
		AddVertex(j);
	}

	AddDirectedEdge(i, j, weight, false);
	AddDirectedEdge(j, i, weight, false);
}


void IncidenceGraph::RemoveEdge(int i, int j)	
{
	auto i_range = incidences.equal_range(i);
	for (auto it = i_range.first; it != i_range.second; it++) {
		if (it->second.i == i && it->second.j == j) {
			incidences.erase(it);
			return;
		}
	}
}


void IncidenceGraph::SetEdge(int i, int j, double weight)
{
	auto i_range = incidences.equal_range(i);
	for (auto it = i_range.first; it != i_range.second; it++) {
		if (it->second.i == i && it->second.j == j)
			it->second.weight = weight;
	}
}


Edge IncidenceGraph::GetEdge(int i, int j) const
{
	auto i_range = incidences.equal_range(i);
	for (auto it = i_range.first; it != i_range.second; it++) {
		if (it->second.i == i && it->second.j == j)
			return it->second;
	}

	return Edge::Null;
}


list<Edge> IncidenceGraph::GetEdges(int i) const
{
	auto l = list<Edge>();

	auto i_range = incidences.equal_range(i);
	for (auto it = i_range.first; it != i_range.second; it++) {
		if (it->second.i == i)
			l.push_back(it->second);
	}

	return l;
}


bool IncidenceGraph::ContainsEdge(int i, int j) const
{
	auto i_range = incidences.equal_range(i);
	for (auto it = i_range.first; it != i_range.second; it++) {
		if (it->second.i == i && it->second.j == j)
			return true;
	}

	return false;
}


int IncidenceGraph::EdgeCount() const
{
	auto n = 0;
	for (auto it = incidences.begin(); it != incidences.end(); it++) {
		if (it->second.IsNull()) continue;
		n++;
	}
	return n;
}
